From 97ae5e751db59ca75419024e0caba69c387e54a8 Mon Sep 17 00:00:00 2001 From: Tim Deegan Date: Thu, 16 Nov 2006 17:07:23 +0000 Subject: [PATCH] [HVM] Decouple the RTC from the PIT periodic timer Signed-off-by: Tim Deegan --- xen/arch/x86/hvm/hvm.c | 17 +++++++ xen/arch/x86/hvm/i8259.c | 12 ----- xen/arch/x86/hvm/rtc.c | 82 +++++++++++++++++++++---------- xen/arch/x86/hvm/svm/svm.c | 23 ++------- xen/arch/x86/hvm/vioapic.c | 4 +- xen/arch/x86/hvm/vmx/vmcs.c | 2 +- xen/arch/x86/hvm/vmx/vmx.c | 22 ++------- xen/include/asm-x86/hvm/hvm.h | 1 + xen/include/asm-x86/hvm/vmx/vmx.h | 1 - xen/include/asm-x86/hvm/vpt.h | 8 ++- 10 files changed, 92 insertions(+), 80 deletions(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 85775d5ae1..a97e3e3838 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -74,6 +74,20 @@ void hvm_set_guest_time(struct vcpu *v, u64 gtime) hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset); } +void hvm_migrate_timers(struct vcpu *v) +{ + struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm; + struct PMTState *vpmt = &v->domain->arch.hvm_domain.pl_time.vpmt; + + if ( pt->enabled ) + { + migrate_timer(&pt->timer, v->processor); + } + migrate_timer(&vcpu_vlapic(v)->vlapic_timer, v->processor); + migrate_timer(&vpmt->timer, v->processor); + rtc_migrate_timers(v); +} + void hvm_do_resume(struct vcpu *v) { ioreq_t *p; @@ -92,6 +106,9 @@ void hvm_do_resume(struct vcpu *v) pickup_deactive_ticks(pt); } + /* Re-enable the RTC timer if needed */ + rtc_thaw(v); + /* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */ p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq; while ( p->state != STATE_IOREQ_NONE ) diff --git a/xen/arch/x86/hvm/i8259.c b/xen/arch/x86/hvm/i8259.c index de61f96c8d..c1710cdbae 100644 --- a/xen/arch/x86/hvm/i8259.c +++ b/xen/arch/x86/hvm/i8259.c @@ -536,8 +536,6 @@ int is_periodic_irq(struct vcpu *v, int irq, int type) int vec; struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm); - struct RTCState *vrtc = - &(v->domain->arch.hvm_domain.pl_time.vrtc); if (pt->irq == 0) { /* Is it pit irq? */ if (type == APIC_DM_EXTINT) @@ -549,16 +547,6 @@ int is_periodic_irq(struct vcpu *v, int irq, int type) return 1; } - if (pt->irq == 8) { /* Or rtc irq? */ - if (type == APIC_DM_EXTINT) - vec = domain_vpic(v->domain)->pics[1].irq_base; - else - vec = domain_vioapic(v->domain)->redirtbl[8].fields.vector; - - if (irq == vec) - return is_rtc_periodic_irq(vrtc); - } - return 0; } diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c index a2ae171d85..b669d60dfe 100644 --- a/xen/arch/x86/hvm/rtc.c +++ b/xen/arch/x86/hvm/rtc.c @@ -30,40 +30,43 @@ /* #define DEBUG_RTC */ -void rtc_periodic_cb(struct vcpu *v, void *opaque) +/* Callback that fires the RTC's periodic interrupt */ +void rtc_pie_callback(void *opaque) { RTCState *s = opaque; - s->cmos_data[RTC_REG_C] |= 0xc0; -} - -int is_rtc_periodic_irq(void *opaque) -{ - RTCState *s = opaque; - return !(s->cmos_data[RTC_REG_C] & RTC_AF || - s->cmos_data[RTC_REG_C] & RTC_UF); + struct hvm_domain *plat = &s->vcpu->domain->arch.hvm_domain; + struct vpic *pic = &plat->vpic; + /* Record that we have fired */ + s->cmos_data[RTC_REG_C] |= (RTC_IRQF|RTC_PF); /* 0xc0 */ + /* Fire */ + pic_set_irq(pic, s->irq, 1); + /* Remember to fire again */ + s->next_pie = NOW() + s->period; + set_timer(&s->pie_timer, s->next_pie); } -static void rtc_timer_update(RTCState *s, int64_t current_time) +/* Enable/configure/disable the periodic timer based on the RTC_PIE and + * RTC_RATE_SELECT settings */ +static void rtc_timer_update(RTCState *s) { int period_code; int period; - period_code = s->cmos_data[RTC_REG_A] & 0x0f; + period_code = s->cmos_data[RTC_REG_A] & RTC_RATE_SELECT; if (period_code != 0 && (s->cmos_data[RTC_REG_B] & RTC_PIE)) { if (period_code <= 2) period_code += 7; period = 1 << (period_code - 1); /* period in 32 Khz cycles */ period = DIV_ROUND((period * 1000000000ULL), 32768); /* period in ns */ - + s->period = period; #ifdef DEBUG_RTC printk("HVM_RTC: period = %uns\n", period); #endif - - s->pt = create_periodic_time(period, RTC_IRQ, 0, rtc_periodic_cb, s); - } else if (s->pt) { - destroy_periodic_time(s->pt); - s->pt = NULL; + s->next_pie = NOW() + s->period; + set_timer(&s->pie_timer, s->next_pie); + } else { + stop_timer(&s->pie_timer); } } @@ -105,7 +108,7 @@ static int rtc_ioport_write(void *opaque, uint32_t addr, uint32_t data) /* UIP bit is read only */ s->cmos_data[RTC_REG_A] = (data & ~RTC_UIP) | (s->cmos_data[RTC_REG_A] & RTC_UIP); - rtc_timer_update(s, hvm_get_clock(s->vcpu)); + rtc_timer_update(s); break; case RTC_REG_B: if (data & RTC_SET) { @@ -119,14 +122,14 @@ static int rtc_ioport_write(void *opaque, uint32_t addr, uint32_t data) } } s->cmos_data[RTC_REG_B] = data; - rtc_timer_update(s, hvm_get_clock(s->vcpu)); + rtc_timer_update(s); break; case RTC_REG_C: case RTC_REG_D: /* cannot write to them */ break; - return 1; } + return 1; } return 0; } @@ -172,7 +175,7 @@ static void rtc_copy_date(RTCState *s) s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec); s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min); - if (s->cmos_data[RTC_REG_B] & 0x02) { + if (s->cmos_data[RTC_REG_B] & RTC_24H) { /* 24 hour format */ s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour); } else { @@ -245,7 +248,7 @@ static void rtc_update_second(void *opaque) RTCState *s = opaque; /* if the oscillator is not in normal operation, we do not update */ - if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) { + if ((s->cmos_data[RTC_REG_A] & RTC_DIV_CTL) != RTC_REF_CLCK_32KHZ) { s->next_second_time += 1000000000ULL; set_timer(&s->second_timer, s->next_second_time); } else { @@ -361,22 +364,48 @@ static int handle_rtc_io(ioreq_t *p) return 0; } +/* Stop the periodic interrupts from this RTC */ +void rtc_freeze(struct vcpu *v) +{ + RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc; + stop_timer(&s->pie_timer); +} + +/* Start them again */ +void rtc_thaw(struct vcpu *v) +{ + RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc; + if ( (s->cmos_data[RTC_REG_A] & RTC_RATE_SELECT) /* Period is not zero */ + && (s->cmos_data[RTC_REG_B] & RTC_PIE) ) + set_timer(&s->pie_timer, s->next_pie); +} + +/* Move the RTC timers on to this vcpu's current cpu */ +void rtc_migrate_timers(struct vcpu *v) +{ + RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc; + migrate_timer(&s->second_timer, v->processor); + migrate_timer(&s->second_timer2, v->processor); + migrate_timer(&s->pie_timer, v->processor); +} + void rtc_init(struct vcpu *v, int base, int irq) { RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc; s->vcpu = v; s->irq = irq; - s->cmos_data[RTC_REG_A] = 0x26; - s->cmos_data[RTC_REG_B] = 0x02; - s->cmos_data[RTC_REG_C] = 0x00; - s->cmos_data[RTC_REG_D] = 0x80; + s->cmos_data[RTC_REG_A] = RTC_REF_CLCK_32KHZ | 6; /* ~1kHz */ + s->cmos_data[RTC_REG_B] = RTC_24H; + s->cmos_data[RTC_REG_C] = 0; + s->cmos_data[RTC_REG_D] = RTC_VRT; s->current_tm = gmtime(get_localtime(v->domain)); rtc_copy_date(s); init_timer(&s->second_timer, rtc_update_second, s, v->processor); init_timer(&s->second_timer2, rtc_update_second2, s, v->processor); + init_timer(&s->pie_timer, rtc_pie_callback, s, v->processor); s->next_second_time = NOW() + 1000000000ULL; set_timer(&s->second_timer2, s->next_second_time); @@ -390,4 +419,5 @@ void rtc_deinit(struct domain *d) kill_timer(&s->second_timer); kill_timer(&s->second_timer2); + kill_timer(&s->pie_timer); } diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 8528d23b32..9eb54caaa6 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -723,7 +723,10 @@ static void svm_freeze_time(struct vcpu *v) && !v->arch.hvm_vcpu.guest_time ) { v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v); if ( test_bit(_VCPUF_blocked, &v->vcpu_flags) ) + { stop_timer(&pt->timer); + rtc_freeze(v); + } } } @@ -850,24 +853,6 @@ int start_svm(void) } -static void svm_migrate_timers(struct vcpu *v) -{ - struct periodic_time *pt = - &(v->domain->arch.hvm_domain.pl_time.periodic_tm); - struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc; - struct PMTState *vpmt = &v->domain->arch.hvm_domain.pl_time.vpmt; - - if ( pt->enabled ) - { - migrate_timer(&pt->timer, v->processor); - } - migrate_timer(&vcpu_vlapic(v)->vlapic_timer, v->processor); - migrate_timer(&vrtc->second_timer, v->processor); - migrate_timer(&vrtc->second_timer2, v->processor); - migrate_timer(&vpmt->timer, v->processor); -} - - void arch_svm_do_resume(struct vcpu *v) { /* pinning VCPU to a different core? */ @@ -880,7 +865,7 @@ void arch_svm_do_resume(struct vcpu *v) printk("VCPU core pinned: %d to %d\n", v->arch.hvm_svm.launch_core, smp_processor_id() ); v->arch.hvm_svm.launch_core = smp_processor_id(); - svm_migrate_timers( v ); + hvm_migrate_timers( v ); hvm_do_resume( v ); reset_stack_and_jump( svm_asm_do_resume ); } diff --git a/xen/arch/x86/hvm/vioapic.c b/xen/arch/x86/hvm/vioapic.c index c32ece46e3..2ac4262bfe 100644 --- a/xen/arch/x86/hvm/vioapic.c +++ b/xen/arch/x86/hvm/vioapic.c @@ -471,8 +471,8 @@ void vioapic_set_irq(struct domain *d, int irq, int level) struct vioapic *vioapic = domain_vioapic(d); uint32_t bit; - HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_set_irq " - "irq %x level %x\n", irq, level); + HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_set_irq irq %x level %x", + irq, level); if ( (irq < 0) || (irq >= VIOAPIC_NUM_PINS) ) return; diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index 45878d1c03..cee05bc552 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -486,7 +486,7 @@ void arch_vmx_do_resume(struct vcpu *v) { vmx_clear_vmcs(v); vmx_load_vmcs(v); - vmx_migrate_timers(v); + hvm_migrate_timers(v); vmx_set_host_env(v); } diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index e7d3f8a942..8382c6e148 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -376,14 +376,18 @@ static inline void vmx_restore_dr(struct vcpu *v) static void vmx_freeze_time(struct vcpu *v) { - struct periodic_time *pt=&v->domain->arch.hvm_domain.pl_time.periodic_tm; + struct hvm_domain *plat = &v->domain->arch.hvm_domain; + struct periodic_time *pt = &plat->pl_time.periodic_tm; if ( pt->enabled && pt->first_injected && (v->vcpu_id == pt->bind_vcpu) && !v->arch.hvm_vcpu.guest_time ) { v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v); if ( !test_bit(_VCPUF_blocked, &v->vcpu_flags) ) + { stop_timer(&pt->timer); + rtc_freeze(v); + } } } @@ -409,22 +413,6 @@ static void stop_vmx(void) clear_in_cr4(X86_CR4_VMXE); } -void vmx_migrate_timers(struct vcpu *v) -{ - struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm; - struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc; - struct PMTState *vpmt = &v->domain->arch.hvm_domain.pl_time.vpmt; - - if ( pt->enabled ) - { - migrate_timer(&pt->timer, v->processor); - } - migrate_timer(&vcpu_vlapic(v)->vlapic_timer, v->processor); - migrate_timer(&vrtc->second_timer, v->processor); - migrate_timer(&vrtc->second_timer2, v->processor); - migrate_timer(&vpmt->timer, v->processor); -} - static void vmx_store_cpu_guest_regs( struct vcpu *v, struct cpu_user_regs *regs, unsigned long *crs) { diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index 6576e20839..69e6d1c960 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -161,6 +161,7 @@ hvm_get_guest_ctrl_reg(struct vcpu *v, unsigned int num) void hvm_stts(struct vcpu *v); void hvm_set_guest_time(struct vcpu *v, u64 gtime); +void hvm_migrate_timers(struct vcpu *v); void hvm_do_resume(struct vcpu *v); static inline void diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h index eca3b683ed..881b2de38a 100644 --- a/xen/include/asm-x86/hvm/vmx/vmx.h +++ b/xen/include/asm-x86/hvm/vmx/vmx.h @@ -29,7 +29,6 @@ extern void vmx_asm_vmexit_handler(struct cpu_user_regs); extern void vmx_asm_do_vmentry(void); extern void vmx_intr_assist(void); -extern void vmx_migrate_timers(struct vcpu *v); extern void arch_vmx_do_resume(struct vcpu *); extern void set_guest_time(struct vcpu *v, u64 gtime); diff --git a/xen/include/asm-x86/hvm/vpt.h b/xen/include/asm-x86/hvm/vpt.h index b4492e1d59..8e0e600194 100644 --- a/xen/include/asm-x86/hvm/vpt.h +++ b/xen/include/asm-x86/hvm/vpt.h @@ -67,8 +67,10 @@ typedef struct RTCState { int64_t next_second_time; struct timer second_timer; struct timer second_timer2; + struct timer pie_timer; + int period; + s_time_t next_pie; struct vcpu *vcpu; - struct periodic_time *pt; } RTCState; #define FREQUENCE_PMTIMER 3579545 @@ -143,9 +145,11 @@ extern void destroy_periodic_time(struct periodic_time *pt); void pit_init(struct vcpu *v, unsigned long cpu_khz); void rtc_init(struct vcpu *v, int base, int irq); void rtc_deinit(struct domain *d); +void rtc_freeze(struct vcpu *v); +void rtc_thaw(struct vcpu *v); +void rtc_migrate_timers(struct vcpu *v); void pmtimer_init(struct vcpu *v, int base); void pmtimer_deinit(struct domain *d); -int is_rtc_periodic_irq(void *opaque); void pt_timer_fn(void *data); void pit_time_fired(struct vcpu *v, void *priv); -- 2.30.2